//
//  http_server.cc
//  iphttpd
//
//  Created by Zhibiao Pan on 11-11-12.
//  Copyright 2011年 PanZhibiao. All rights reserved.
//

#include "http_server.h"

#include <event.h>
#include <evhttp.h>
#include <pthread.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>


int HTTPServer::BindSocket(in_addr_t ip, int port) {
  int r;
  int nfd;
  nfd = socket(AF_INET, SOCK_STREAM, 0);
  if (nfd < 0) return -1;
  
  int one = 1;
  r = setsockopt(nfd, SOL_SOCKET, SO_REUSEADDR, (char *)&one, sizeof(int));
  
  struct sockaddr_in addr;
  memset(&addr, 0, sizeof(addr));
  addr.sin_family = AF_INET;
//  addr.sin_addr.s_addr = INADDR_ANY;
  addr.sin_addr.s_addr = ip;
  addr.sin_port = htons(port);
  
  r = bind(nfd, (struct sockaddr*)&addr, sizeof(addr));
  if (r < 0) return -1;
  r = listen(nfd, 10240);
  if (r < 0) return -1;
  
  int flags;
  if ((flags = fcntl(nfd, F_GETFL, 0)) < 0 || fcntl(nfd, F_SETFL, flags | O_NONBLOCK) < 0)
    return -1;
  
  return nfd;
}

int HTTPServer::run(const char *ip, int port, int nthreads,
                    void (*cb)(struct evhttp_request *, void *)) {
  int r;
  int nfd = BindSocket(inet_addr(ip), port);
  if (nfd < 0) return -1;
  pthread_t ths[nthreads];
  for (int i = 0; i < nthreads; i++) {
    struct event_base *base = event_init();
    if (base == NULL) return -1;
    struct evhttp *httpd = evhttp_new(base);
    if (httpd == NULL) return -1;
    r = evhttp_accept_socket(httpd, nfd);
    if (r != 0) return -1;
    evhttp_set_gencb(httpd, cb, this);
    r = pthread_create(&ths[i], NULL, HTTPServer::Dispatch, base);
    if (r != 0) return -1;
  }
  for (int i = 0; i < nthreads; i++) {
    pthread_join(ths[i], NULL);
  }
  return 0;
}

void* HTTPServer::Dispatch(void *arg) {
  event_base_dispatch((struct event_base*)arg);
  return NULL;
}


